{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch_geometric.data import Data\n",
    "\n",
    "edge_index = torch.tensor([[0, 1, 1, 2],\n",
    "                           [1, 0, 2, 1]], dtype=torch.long)\n",
    "x = torch.tensor([[-1], [0], [1]], dtype=torch.float)\n",
    "\n",
    "data = Data(x=x, edge_index=edge_index)\n",
    "# >>> Data(edge_index=[2, 4], x=[3, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'tmp\\\\graph.png'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from graphviz import Digraph\n",
    "\n",
    "\n",
    "def visualize_graph(edge_index, node_labels=None):\n",
    "    dot = Digraph()\n",
    "\n",
    "    # Add nodes\n",
    "    for i in range(edge_index.max().item() + 1):\n",
    "        label = str(i)\n",
    "        if node_labels is not None:\n",
    "            label = f'{i}: {node_labels[i].item()}'\n",
    "    dot.node(str(i), label)\n",
    "\n",
    "    # Add edges\n",
    "    for i, j in edge_index.t().tolist():\n",
    "        dot.edge(str(i), str(j))\n",
    "\n",
    "    return dot\n",
    "\n",
    "\n",
    "# Visualize the graph\n",
    "dot = visualize_graph(edge_index, x)\n",
    "dot.render('./tmp/graph', format='png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from graphviz import Digraph\n",
    "from PIL import Image as PILImage\n",
    "import matplotlib.pyplot as plt\n",
    "import io\n",
    "\n",
    "# 创建一个 Digraph 对象\n",
    "dot = Digraph()\n",
    "\n",
    "# 添加节点和边\n",
    "dot.node('A', 'Node A')\n",
    "dot.node('B', 'Node B')\n",
    "dot.node('C', 'Node C')\n",
    "dot.edge('A', 'B')\n",
    "dot.edge('A', 'C')\n",
    "\n",
    "# 生成图像并转换为 PIL 图像对象\n",
    "png_bytes = dot.pipe(format='png')\n",
    "img = PILImage.open(io.BytesIO(png_bytes))\n",
    "\n",
    "# 使用 matplotlib 显示图像\n",
    "plt.imshow(img)\n",
    "plt.axis('off')  # 关闭坐标轴\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch_geometric.datasets import TUDataset\n",
    "\n",
    "dataset = TUDataset(root='./tmp/ENZYMES', name='ENZYMES')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(600, 6, 3)"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(dataset), dataset.num_classes, dataset.num_node_features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "batch= DataBatch(edge_index=[2, 4060], x=[1060, 21], y=[32], batch=[1060], ptr=[33])\n",
      "batch.num_graphs= 32\n"
     ]
    }
   ],
   "source": [
    "from torch_geometric.datasets import TUDataset\n",
    "from torch_geometric.loader import DataLoader\n",
    "\n",
    "dataset = TUDataset(root='./tmp/ENZYMES', name='ENZYMES', use_node_attr=True)\n",
    "loader = DataLoader(dataset, batch_size=32, shuffle=True)\n",
    "\n",
    "for batch in loader:\n",
    "    print(f\"{batch= }\")\n",
    "    print(f\"{batch.num_graphs= }\")\n",
    "    break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'tmp\\\\graph.png'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from torch_geometric.data import Data\n",
    "import torch\n",
    "from graphviz import Digraph\n",
    "dot = Digraph()\n",
    "dot.node('A', 'Node A')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.randn(9, 1)\n",
    "edge_index = torch.tensor([(0, 1), (0, 2), (1, 3), (1, 4), (1, 5), (2, 6), (2, 7), (2, 8)])\n",
    "data = Data(x=x, edge_index=edge_index)\n",
    "for i in range(data.num_nodes):\n",
    "    dot.node(str(i+1))\n",
    "for i in data.edge_index.tolist():\n",
    "    dot.edge(str(i[0]+1), str(i[1]+1))\n",
    "dot.render('./tmp/graph', format='png')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
